﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace TFSTools.TFSLibrary
{
    public class TFSWorkItem : TFSServerEntity
    {
        private WorkItem serverWorkItem;
        private int tfsWorkItemId;
        private TFSFieldInfoCollection fields = null;
        private TFSRevisionCollection revisions = null;
        private TFSWorkItemType workItemType = null;
        
        private string originalState;
        private string originalReason;
        private TFSWorkItemTransition newTransition;
        private string[] availableReasons;

        internal TFSWorkItem(ITFSConnection connection, WorkItem workItem)
            : base(connection)
        {
            this.serverWorkItem = workItem;
            this.tfsWorkItemId = workItem.Id;

            this.originalState = workItem.State;
            this.originalReason = workItem.Reason;
            this.UpdateReasonDueToStateChange();
        }

        internal WorkItem ServerEntity { get { return this.serverWorkItem; } }

        public int Id { get { return this.tfsWorkItemId; } }

        ////public bool IsOwner
        ////{
        ////    get
        ////    {
        ////        try { return (tfsWorkItem.Fields["Assigned To"].Value.ToString().ToLower() == tfsConnection.AuthenticatedUserName.ToLower()); }
        ////        catch { }
        ////        return false;
        ////    }
        ////}

        public string Title 
        {
            get { return this.serverWorkItem.Title; }
            set { this.serverWorkItem.Title = value; }
        }

        public string State 
        {
            get { return this.serverWorkItem.State; }
            set 
            {
                if (this.serverWorkItem.State != value)
                {
                    this.serverWorkItem.State = value;
                    this.newTransition = this.workItemType.GetTransition(this.originalState, this.State);
                    this.UpdateReasonDueToStateChange();
                }
            }
        }

        public string[] AvailableStates
        {
            get
            {
                var availableStates = new List<string>(from transition
                                                       in this.WorkItemType.GetTransitions(this.State)
                                                       select transition.To);

                if (!availableStates.Contains(this.State))
                {
                    availableStates.Add(this.State);
                }

                availableStates.Sort();

                return availableStates.ToArray();
            }
        }

        private void UpdateReasonDueToStateChange()
        {
            if (this.IsStateChanged)
            {
                var reasons = this.newTransition.Reasons;

                List<string> reasonList = new List<string>(reasons.Count);

                foreach (var reason in reasons)
                {
                    reasonList.Add(reason.Value);

                    if (reason.IsDefault)
                    {
                        this.serverWorkItem.Reason = reason.Value;
                    }
                }

                reasonList.Sort();
                this.availableReasons = reasonList.ToArray();
            }
            else
            {
                this.SetOriginalReason();
            }
        }

        private void SetOriginalReason()
        {
            if (this.serverWorkItem.Reason != this.originalReason)
            {
                this.serverWorkItem.Reason = this.originalReason;
            }

            this.availableReasons = new string[1];
            this.availableReasons[0] = this.originalReason;
        }

        public string Reason 
        {
            get { return this.serverWorkItem.Reason; }
            set { this.serverWorkItem.Reason = value; }
        }

        public string[] AvailableReasons
        {
            get
            {
                return this.availableReasons;
            }
        }

        public bool IsStateChanged
        {
            get
            {
                return this.originalState != this.State && this.newTransition != null;
            }
        }

        public string Description 
        {
            get { return this.serverWorkItem.Description; }
            set { this.serverWorkItem.Description = value; }
        }

        public bool IsDirty { get { return this.serverWorkItem.IsDirty; } }

        public TFSWorkItemType WorkItemType
        {
            get
            {
                if (this.workItemType == null)
                {
                    this.workItemType = new TFSWorkItemType(this.Connection, this.serverWorkItem.Type);
                }

                return this.workItemType;
            }
        }

        public int TreeLevel { get; set; }

        public string TreeTitle
        {
            get
            {
                if (this.TreeLevel > 0)
                {
                    string treespace = new string(' ', this.TreeLevel * 4);
                    return treespace + this.Title;
                }
                else
                {
                    return this.Title;
                }
            }
        }

        public void AddAttachment(string path)
        {
            this.AddAttachment(path, Path.GetFileName(path));
        }

        public void AddAttachment(string path, string comment)
        {
            if (!File.Exists(path))
            {
                return;
            }

            if (string.IsNullOrEmpty(comment))
            {
                return;
            }

            Attachment newAtt = new Attachment(path, comment);
            this.serverWorkItem.Attachments.Add(newAtt);
        }

        public TFSAttachmentCollection GetAttachments()
        {
            return TFSAttachmentCollection.Create(this.Connection, this.serverWorkItem.Attachments);
        }

        public TFSFieldInfoCollection Fields
        {
            get
            {
                if (this.fields == null)
                {
                    this.fields = TFSFieldInfoCollection.Create(this.Connection, this.serverWorkItem.Fields);
                }

                return this.fields;
            }
        }

        #region Field Retrieval Methods

        ////public object GetFieldValueFromReferenceName(string fieldReferenceName)
        ////{
        ////    var fields = tfsWorkItem.Fields;

        ////    foreach (Field field in fields)
        ////    {
        ////        if (field.FieldDefinition.ReferenceName == fieldReferenceName)
        ////        {
        ////            return field.Value;
        ////        }
        ////    }

        ////    return fields[fieldReferenceName];
        ////}

        ////public object GetFieldValue(TFSCoreField coreField)
        ////{
        ////    CoreField cr = (CoreField)(int)coreField;
        ////    return tfsWorkItem.Fields[cr].Value;
        ////}

        ////public object GetFieldValue(int index)
        ////{
        ////    return tfsWorkItem.Fields[index].Value;
        ////}

        ////public object GetFieldValue(string fieldName)
        ////{
        ////    return tfsWorkItem.Fields[fieldName].Value;
        ////}

        ////public string GetFieldValueString(string fieldName)
        ////{
        ////    var field = tfsWorkItem.Fields[fieldName];
        ////    string result = field.Value.ToString();
        ////    return result;
        ////}

        ////public int GetFieldValueInt32(string fieldName)
        ////{
        ////    return (int)tfsWorkItem.Fields[fieldName].Value;
        ////}

        ////public TFSFieldInfo GetFieldInfo(string fieldName)
        ////{
        ////    return new TFSFieldInfo(tfsConnection, tfsWorkItem.Fields[fieldName]);
        ////}

        #endregion

        public TFSRevisionCollection Revisions
        {
            get
            {
                if (this.revisions == null)
                {
                    this.revisions = TFSRevisionCollection.Create(this.Connection, this.serverWorkItem.Revisions);
                }

                return this.revisions;
            }
        }

        public void Save()
        {
            this.serverWorkItem.Save();
        }

        public override string ToString()
        {
            return this.Title;
        }
    }

    public sealed class TFSWorkItemCollection : TFSServerEntityCollection<TFSWorkItem>
    {
        public TFSWorkItemCollection(ITFSConnection connection)
            : base(connection)
        {
        }

        public TFSWorkItemCollection(ITFSConnection connection, IList<TFSWorkItem> list)
            : base(connection, list)
        {
        }

        public TFSWorkItemCollection(ITFSConnection connection, int capacity)
            : base(connection, capacity)
        {
        }

        internal static TFSWorkItemCollection Create(ITFSConnection connection, WorkItemCollection collection)
        {
            if (collection != null)
            {
                var list = new List<TFSWorkItem>(collection.Count);

                foreach (WorkItem workItem in collection)
                {
                    list.Add(new TFSWorkItem(connection, workItem));
                }
                
                return new TFSWorkItemCollection(connection, list);
            }

            return new TFSWorkItemCollection(connection, new List<TFSWorkItem>());
        }

        public TFSWorkItemCollection FilterByAssignedToMe()
        {
            var me = this.Connection.GroupSecurity.GetCurrentAuthorizedUserIdentity().DisplayName;
            return new TFSWorkItemCollection(Connection, this.Where(x => x.Fields["Assigned To"].ValueString == me).ToList());
        }
    }

// [Title], TVIS00000069 - SUC-DN13 - Confirmation Prompt is missing when deactivating equipment
// [State], Resolved
// [Rev], 2
// [Changed By], Irwin, Mark (MTO)
// [Issue], No
// [State Change Date], 13/11/2008 10:20:43 AM
// [Activated Date], 05/11/2008 11:33:48 AM
// [Activated By], Irwin, Mark (MTO)
// [Resolved Date], 13/11/2008 10:20:43 AM
// [Reason], Fixed
// [Resolved Reason], New
// [Assigned To], Irwin, Mark (MTO)
// [Work Item Type], Bug
// [Priority], 2
// [Triage], Approved
// [Rank], 2
// [Test Name], 
// [Test Id], 
// [Test Path], 
// [Created Date], 05/11/2008 11:33:48 AM
// [Created By], Irwin, Mark (MTO)
// [Found In], 
// [Integration Build], 
// [Closed By], 
// [Closed Date], 
// [Resolved By], Irwin, Mark (MTO)
// [Description], 1. Select 'Maintain Equipment Record' from the TVIS Navigator pane.
// [History], Resolved with changeset 14512.
// [RelatedLinkCount], 0
// [Iteration Path], TVIS_Home
// [IterationID], 341
// [ExternalLinkCount], 1
// [Team Project], TVIS_Home
// [HyperLinkCount], 0
// [AttachedFileCount], 0
// [Node Name], TVIS_Home
// [Area Path], TVIS_Home
// [Revised Date], 01/01/9999 12:00:00 AM
// [Changed Date], 13/11/2008 10:20:43 AM
// [ID], 2258
// [AreaID], 341
// [Authorized As], Irwin, Mark (MTO)
}
